package com.deepwiki.service;

import com.deepwiki.controller.WarehouseController;
import com.deepwiki.domain.entity.Document;
import com.deepwiki.domain.entity.Warehouse;
import com.deepwiki.domain.enums.WarehouseStatus;
import com.deepwiki.dto.GitRepositoryInfo;
import com.deepwiki.storage.impl.ElasticsearchStorageStrategy;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDateTime;
import java.util.List;
import java.util.UUID;
import java.util.Map;
import java.util.HashMap;
import java.util.Collections;
import java.util.ArrayList;
import java.util.stream.Collectors;

/**
 * 仓库服务 - 修正版
 * 使用ES存储替代JPA Repository，支持新的索引结构
 */
@Service
public class WarehouseService {

    private static final Logger logger = LoggerFactory.getLogger(WarehouseService.class);

    private final ElasticsearchStorageStrategy elasticsearchStorage;
    private final DocumentGenerationService documentGenerationService;
    private final DirectoryTreeService directoryTreeService;

    @Autowired
    public WarehouseService(ElasticsearchStorageStrategy elasticsearchStorage,
                           DocumentGenerationService documentGenerationService,
                           DirectoryTreeService directoryTreeService) {
        this.elasticsearchStorage = elasticsearchStorage;
        this.documentGenerationService = documentGenerationService;
        this.directoryTreeService = directoryTreeService;
    }

    /**
     * 创建仓库并开始wiki生成
     *
     * @param request 创建请求
     * @return 创建的仓库
     */
    @Transactional
    public Warehouse createWarehouse(WarehouseController.CreateWarehouseRequest request) {
        try {
            logger.info("开始创建仓库: {}", request.getAddress());
            
            // 检查仓库是否已存在
            if (warehouseExists(request.getAddress())) {
                throw new IllegalArgumentException("仓库已存在: " + request.getAddress());
            }
            
            // 创建仓库实体
            Warehouse warehouse = new Warehouse();
            warehouse.setId(UUID.randomUUID().toString().replace("-", ""));
            warehouse.setAddress(request.getAddress());
            warehouse.setName(request.getName());
            warehouse.setDescription(request.getDescription());
            warehouse.setType(request.getType());
            warehouse.setBranch(request.getBranch());
            warehouse.setGitUsername(request.getUsername());
            warehouse.setGitPassword(request.getPassword());
            warehouse.setEmail(request.getEmail());
            warehouse.setStatus(WarehouseStatus.PENDING);
            warehouse.setIsDeleted(false);
            warehouse.setCreateTime(LocalDateTime.now());
            warehouse.setUpdateTime(LocalDateTime.now());
            
            // 保存到ES
            saveWarehouseToElasticsearch(warehouse);
            
            // 异步开始wiki生成
            processWarehouseAsync(warehouse.getId());
            
            logger.info("仓库创建成功: {}, ID: {}", request.getAddress(), warehouse.getId());
            return warehouse;
            
        } catch (Exception e) {
            logger.error("创建仓库失败: {}", request.getAddress(), e);
            throw new RuntimeException("创建仓库失败: " + e.getMessage(), e);
        }
    }

    /**
     * 检查仓库是否已存在
     */
    private boolean warehouseExists(String address) {
        try {
            return elasticsearchStorage.warehouseExists(address);
        } catch (Exception e) {
            logger.error("检查仓库是否存在失败: {}", address, e);
            return false;
        }
    }

    /**
     * 保存仓库到ES
     */
    private void saveWarehouseToElasticsearch(Warehouse warehouse) {
        try {
            ElasticsearchStorageStrategy.WarehouseInfo warehouseInfo = new ElasticsearchStorageStrategy.WarehouseInfo();
            warehouseInfo.warehouseId = warehouse.getId();
            warehouseInfo.organizationName = warehouse.getOrganizationName();
            warehouseInfo.name = warehouse.getName();
            warehouseInfo.description = warehouse.getDescription();
            warehouseInfo.address = warehouse.getAddress();
            warehouseInfo.type = warehouse.getType();
            warehouseInfo.branch = warehouse.getBranch();
            warehouseInfo.gitUsername = warehouse.getGitUsername();
            warehouseInfo.gitPassword = warehouse.getGitPassword();
            warehouseInfo.email = warehouse.getEmail();
            warehouseInfo.status = warehouse.getStatus().toString();
            warehouseInfo.error = warehouse.getError();
            warehouseInfo.prompt = warehouse.getPrompt();
            warehouseInfo.version = warehouse.getVersion();
            warehouseInfo.model = warehouse.getModel();
            warehouseInfo.isEmbedded = warehouse.getIsEmbedded();
            warehouseInfo.isRecommended = warehouse.getIsRecommended();
            warehouseInfo.isDeleted = warehouse.getIsDeleted();
            warehouseInfo.optimizedDirectoryStructure = warehouse.getOptimizedDirectoryStructure();
            
            elasticsearchStorage.saveWarehouse(warehouseInfo);
            
        } catch (Exception e) {
            logger.error("保存仓库到ES失败: {}", warehouse.getId(), e);
            throw new RuntimeException("保存仓库失败: " + e.getMessage(), e);
        }
    }

    /**
     * 异步处理仓库wiki生成
     *
     * @param warehouseId 仓库ID
     */
    @Async
    public void processWarehouseAsync(String warehouseId) {
        try {
            logger.info("开始异步处理仓库: {}", warehouseId);
            
            Warehouse warehouse = getWarehouse(warehouseId);
            if (warehouse == null) {
                logger.error("仓库不存在: {}", warehouseId);
                return;
            }
            
            // 更新状态为处理中
            warehouse.setStatus(WarehouseStatus.PROCESSING);
            warehouse.setUpdateTime(LocalDateTime.now());
            saveWarehouseToElasticsearch(warehouse);
            
            // 验证本地路径是否存在
            String localPath = warehouse.getAddress(); // 现在address字段直接存储本地路径
            Path projectPath = Paths.get(localPath);
            
            if (!Files.exists(projectPath)) {
                logger.error("本地代码路径不存在: {}", localPath);
                warehouse.setStatus(WarehouseStatus.FAILED);
                warehouse.setError("本地代码路径不存在: " + localPath);
                warehouse.setUpdateTime(LocalDateTime.now());
                saveWarehouseToElasticsearch(warehouse);
                return;
            }
            
            if (!Files.isDirectory(projectPath)) {
                logger.error("指定路径不是目录: {}", localPath);
                warehouse.setStatus(WarehouseStatus.FAILED);
                warehouse.setError("指定路径不是目录: " + localPath);
                warehouse.setUpdateTime(LocalDateTime.now());
                saveWarehouseToElasticsearch(warehouse);
                return;
            }
            
            // 从本地路径解析项目信息
            String projectName = projectPath.getFileName().toString();
            String organizationName = projectPath.getParent() != null ? 
                    projectPath.getParent().getFileName().toString() : "unknown";
            
            // 更新仓库信息
            if (warehouse.getName() == null || warehouse.getName().trim().isEmpty()) {
                warehouse.setName(projectName);
            }
            warehouse.setOrganizationName(organizationName);
            
            // 尝试从.git目录获取版本信息（如果存在）
            String version = extractGitVersionFromLocalRepo(localPath);
            warehouse.setVersion(version);
            warehouse.setUpdateTime(LocalDateTime.now());
            
            saveWarehouseToElasticsearch(warehouse);
            
            // 创建或更新文档记录
            Document document = getDocumentByWarehouseId(warehouseId);
            if (document == null) {
                document = new Document();
                document.setId(UUID.randomUUID().toString().replace("-", ""));
                document.setWarehouseId(warehouseId);
                document.setIsDeleted(false);
                document.setCreateTime(LocalDateTime.now());
            }
            
            document.setGitPath(localPath); // 直接使用本地路径
            document.setStatus(WarehouseStatus.PROCESSING);
            document.setLastUpdate(LocalDateTime.now());
            document.setUpdateTime(LocalDateTime.now());
            
            // 保存文档记录到commits索引
            saveDocumentToElasticsearch(document);
            
            logger.info("开始处理本地项目: {} -> {}", projectName, localPath);
            
            // 生成wiki文档
            documentGenerationService.generateDocuments(warehouse, document);
            
            // 生成目录树
            directoryTreeService.generateDirectoryTree(warehouseId);
            
            // 更新状态为完成
            warehouse.setStatus(WarehouseStatus.COMPLETED);
            warehouse.setUpdateTime(LocalDateTime.now());
            saveWarehouseToElasticsearch(warehouse);
            
            document.setStatus(WarehouseStatus.COMPLETED);
            document.setUpdateTime(LocalDateTime.now());
            saveDocumentToElasticsearch(document);
            
            logger.info("仓库处理完成: {}", warehouseId);
            
        } catch (Exception e) {
            logger.error("处理仓库失败: {}", warehouseId, e);
            
            // 更新失败状态
            try {
                Warehouse warehouse = getWarehouse(warehouseId);
                if (warehouse != null) {
                    warehouse.setStatus(WarehouseStatus.FAILED);
                    warehouse.setError(e.getMessage());
                    warehouse.setUpdateTime(LocalDateTime.now());
                    saveWarehouseToElasticsearch(warehouse);
                }
            } catch (Exception ex) {
                logger.error("更新仓库失败状态时发生错误: {}", warehouseId, ex);
            }
        }
    }

    /**
     * 保存文档记录到ES commits索引
     */
    private void saveDocumentToElasticsearch(Document document) {
        try {
            ElasticsearchStorageStrategy.CommitInfo commitInfo = new ElasticsearchStorageStrategy.CommitInfo();
            commitInfo.commitId = document.getId();
            commitInfo.documentId = document.getId();
            commitInfo.gitPath = document.getGitPath();
            commitInfo.status = document.getStatus().toString();
            commitInfo.likeCount = document.getLikeCount();
            commitInfo.commentCount = document.getCommentCount();
            commitInfo.lastUpdate = System.currentTimeMillis();
            commitInfo.isDeleted = document.getIsDeleted();
            
            elasticsearchStorage.saveCommit(document.getWarehouseId(), commitInfo);
            
        } catch (Exception e) {
            logger.error("保存文档记录到ES失败: {}", document.getId(), e);
        }
    }

    /**
     * 从ES获取文档记录
     */
    private Document getDocumentByWarehouseId(String warehouseId) {
        try {
            ElasticsearchStorageStrategy.CommitInfo commitInfo = elasticsearchStorage.getDocumentByWarehouseId(warehouseId);
            if (commitInfo != null) {
                // 转换CommitInfo为Document对象
                Document document = new Document();
                document.setId(commitInfo.documentId);
                document.setWarehouseId(commitInfo.warehouseId);
                document.setGitPath(commitInfo.gitPath);
                document.setStatus(WarehouseStatus.valueOf(commitInfo.status));
                document.setLikeCount(commitInfo.likeCount != null ? commitInfo.likeCount.intValue() : 0);
                document.setCommentCount(commitInfo.commentCount != null ? commitInfo.commentCount.intValue() : 0);
                document.setIsDeleted(commitInfo.isDeleted);
                return document;
            }
            return null;
        } catch (Exception e) {
            logger.error("从ES获取文档记录失败: {}", warehouseId, e);
            return null;
        }
    }

    /**
     * 从本地Git仓库提取版本信息
     */
    private String extractGitVersionFromLocalRepo(String localPath) {
        try {
            Path gitDir = Paths.get(localPath, ".git");
            if (!Files.exists(gitDir)) {
                logger.debug("本地项目不是Git仓库: {}", localPath);
                return "unknown";
            }
            
            // 尝试读取HEAD文件获取当前分支的commit hash
            Path headFile = gitDir.resolve("HEAD");
            if (Files.exists(headFile)) {
                String headContent = Files.readString(headFile).trim();
                
                if (headContent.startsWith("ref: ")) {
                    // 指向分支引用
                    String refPath = headContent.substring(5);
                    Path refFile = gitDir.resolve(refPath);
                    if (Files.exists(refFile)) {
                        String commit = Files.readString(refFile).trim();
                        return commit.substring(0, Math.min(8, commit.length())); // 返回短commit hash
                    }
                } else if (headContent.matches("[0-9a-f]{40}")) {
                    // 直接是commit hash
                    return headContent.substring(0, 8);
                }
            }
            
            return "unknown";
            
        } catch (Exception e) {
            logger.debug("提取Git版本信息失败: {}", localPath, e);
            return "unknown";
        }
    }

    /**
     * 获取仓库
     *
     * @param warehouseId 仓库ID
     * @return 仓库
     */
    public Warehouse getWarehouse(String warehouseId) {
        try {
            ElasticsearchStorageStrategy.WarehouseInfo warehouseInfo = elasticsearchStorage.getWarehouse(warehouseId);
            if (warehouseInfo != null) {
                return convertToWarehouse(warehouseInfo);
            }
            return null;
        } catch (Exception e) {
            logger.error("从ES获取仓库失败: {}", warehouseId, e);
            return null;
        }
    }

    /**
     * 获取所有仓库
     *
     * @return 仓库列表
     */
    public List<Warehouse> getAllWarehouses() {
        try {
            List<ElasticsearchStorageStrategy.WarehouseInfo> warehouseInfos = elasticsearchStorage.getAllWarehouses();
            return warehouseInfos.stream()
                    .map(this::convertToWarehouse)
                    .collect(Collectors.toList());
        } catch (Exception e) {
            logger.error("从ES获取所有仓库失败", e);
            return new ArrayList<>();
        }
    }

    /**
     * 重新生成仓库wiki
     *
     * @param warehouseId 仓库ID
     */
    public void regenerateWarehouse(String warehouseId) {
        try {
            Warehouse warehouse = getWarehouse(warehouseId);
            if (warehouse == null) {
                throw new IllegalArgumentException("仓库不存在: " + warehouseId);
            }
            
            // 重置状态
            warehouse.setStatus(WarehouseStatus.PENDING);
            warehouse.setError(null);
            warehouse.setUpdateTime(LocalDateTime.now());
            saveWarehouseToElasticsearch(warehouse);
            
            // 删除旧的目录树
            directoryTreeService.deleteDirectoryTree(warehouseId);
            
            // 异步重新处理
            processWarehouseAsync(warehouseId);
            
            logger.info("重新生成仓库wiki任务已启动: {}", warehouseId);
            
        } catch (Exception e) {
            logger.error("重新生成仓库wiki失败: {}", warehouseId, e);
            throw new RuntimeException("重新生成仓库wiki失败: " + e.getMessage(), e);
        }
    }

    /**
     * 删除仓库
     *
     * @param warehouseId 仓库ID
     */
    @Transactional
    public void deleteWarehouse(String warehouseId) {
        try {
            Warehouse warehouse = getWarehouse(warehouseId);
            if (warehouse == null) {
                throw new IllegalArgumentException("仓库不存在: " + warehouseId);
            }
            
            // 软删除仓库
            warehouse.setIsDeleted(true);
            warehouse.setUpdateTime(LocalDateTime.now());
            saveWarehouseToElasticsearch(warehouse);
            
            // 软删除相关文档
            Document document = getDocumentByWarehouseId(warehouseId);
            if (document != null) {
                document.setIsDeleted(true);
                document.setUpdateTime(LocalDateTime.now());
                saveDocumentToElasticsearch(document);
            }
            
            // 删除目录树文件
            directoryTreeService.deleteDirectoryTree(warehouseId);
            
            logger.info("仓库删除成功: {}", warehouseId);
            
        } catch (Exception e) {
            logger.error("删除仓库失败: {}", warehouseId, e);
            throw new RuntimeException("删除仓库失败: " + e.getMessage(), e);
        }
    }

    /**
     * 获取仓库统计信息
     *
     * @return 统计信息
     */
    public Map<String, Object> getWarehouseStats() {
        try {
            Map<String, Long> stats = elasticsearchStorage.getWarehouseStats();
            
            Map<String, Object> result = new HashMap<>();
            result.putAll(stats);
            
            return result;
            
        } catch (Exception e) {
            logger.error("获取仓库统计信息失败", e);
            return Collections.emptyMap();
        }
    }

    /**
     * 根据状态获取仓库列表
     *
     * @param status 状态
     * @return 仓库列表
     */
    public List<Warehouse> getWarehousesByStatus(WarehouseStatus status) {
        try {
            List<ElasticsearchStorageStrategy.WarehouseInfo> warehouseInfos = 
                    elasticsearchStorage.getWarehousesByStatus(status.toString());
            return warehouseInfos.stream()
                    .map(this::convertToWarehouse)
                    .collect(Collectors.toList());
        } catch (Exception e) {
            logger.error("根据状态获取仓库失败: {}", status, e);
            return new ArrayList<>();
        }
    }

    /**
     * 更新仓库状态
     *
     * @param warehouseId 仓库ID
     * @param status 新状态
     * @param error 错误信息（可选）
     */
    public void updateWarehouseStatus(String warehouseId, WarehouseStatus status, String error) {
        try {
            Warehouse warehouse = getWarehouse(warehouseId);
            if (warehouse != null) {
                warehouse.setStatus(status);
                warehouse.setError(error);
                warehouse.setUpdateTime(LocalDateTime.now());
                saveWarehouseToElasticsearch(warehouse);
                
                logger.info("仓库状态已更新: {} -> {}", warehouseId, status);
            }
        } catch (Exception e) {
            logger.error("更新仓库状态失败: {}", warehouseId, e);
        }
    }

    /**
     * 搜索仓库
     *
     * @param keyword 关键词
     * @return 搜索结果
     */
    public List<Warehouse> searchWarehouses(String keyword) {
        try {
            List<ElasticsearchStorageStrategy.WarehouseInfo> warehouseInfos = 
                    elasticsearchStorage.searchWarehouses(keyword);
            return warehouseInfos.stream()
                    .map(this::convertToWarehouse)
                    .collect(Collectors.toList());
        } catch (Exception e) {
            logger.error("搜索仓库失败: {}", keyword, e);
            return new ArrayList<>();
        }
    }

    /**
     * 转换WarehouseInfo为Warehouse对象
     */
    private Warehouse convertToWarehouse(ElasticsearchStorageStrategy.WarehouseInfo warehouseInfo) {
        Warehouse warehouse = new Warehouse();
        warehouse.setId(warehouseInfo.warehouseId);
        warehouse.setOrganizationName(warehouseInfo.organizationName);
        warehouse.setName(warehouseInfo.name);
        warehouse.setDescription(warehouseInfo.description);
        warehouse.setAddress(warehouseInfo.address);
        warehouse.setType(warehouseInfo.type);
        warehouse.setBranch(warehouseInfo.branch);
        warehouse.setGitUsername(warehouseInfo.gitUsername);
        warehouse.setGitPassword(warehouseInfo.gitPassword);
        warehouse.setEmail(warehouseInfo.email);
        warehouse.setStatus(WarehouseStatus.valueOf(warehouseInfo.status));
        warehouse.setError(warehouseInfo.error);
        warehouse.setPrompt(warehouseInfo.prompt);
        warehouse.setVersion(warehouseInfo.version);
        warehouse.setModel(warehouseInfo.model);
        warehouse.setIsEmbedded(warehouseInfo.isEmbedded);
        warehouse.setIsRecommended(warehouseInfo.isRecommended);
        warehouse.setIsDeleted(warehouseInfo.isDeleted);
        warehouse.setOptimizedDirectoryStructure(warehouseInfo.optimizedDirectoryStructure);
        return warehouse;
    }
} 